﻿namespace Jhong.Mapper
{
    using System;

    internal static class DataConvertor<TFrom, TTo>
    {
        public static TTo Convert(object input)
        {
            try
            {
                return (TTo)_convertDelegate(input);
            }
            catch
            {
                return default(TTo);
            }
        }

        private static Func<object, object> _convertDelegate;

        private static Type _toType;

        static DataConvertor()
        {
            _toType = typeof(TTo);
            _convertDelegate = CreateConvertDelegate();
        }

        private static Func<object, object> CreateConvertDelegate()
        {
            if (typeof(TFrom) == _toType) return x => x;
            if (_toType == typeof(int)) return CreateSafeConvert(x => System.Convert.ToInt32(x));
            else if (_toType == typeof(Int16)) return CreateSafeConvert(x => System.Convert.ToInt16(x));
            else if (_toType == typeof(Int64)) return CreateSafeConvert(x => System.Convert.ToInt64(x));
            else if (_toType == typeof(UInt16)) return CreateSafeConvert(x => System.Convert.ToUInt16(x));
            else if (_toType == typeof(UInt32)) return CreateSafeConvert(x => System.Convert.ToUInt32(x));
            else if (_toType == typeof(UInt64)) return CreateSafeConvert(x => System.Convert.ToUInt64(x));
            else if (_toType == typeof(Single)) return CreateSafeConvert(x => System.Convert.ToSingle(x));
            else if (_toType == typeof(double)) return CreateSafeConvert(x => System.Convert.ToDouble(x));
            else if (_toType == typeof(decimal)) return CreateSafeConvert(x => System.Convert.ToDecimal(x));
            else if (_toType == typeof(byte)) return CreateSafeConvert(x => System.Convert.ToByte(x));
            else if (_toType == typeof(sbyte)) return CreateSafeConvert(x => System.Convert.ToSByte(x));
            else if (_toType == typeof(bool)) return CreateSafeConvert(x => System.Convert.ToBoolean(x));
            else if (_toType == typeof(string)) return CreateSafeConvert(x => System.Convert.ToString(x));
            else if (_toType == typeof(DateTime)) return CreateSafeConvert(x => System.Convert.ToDateTime(x));
            else if (_toType == typeof(Guid)) return CreateSafeConvert(x => Guid.Parse(System.Convert.ToString(x)));
            else return x => x;
        }

        private static Func<object, object> CreateSafeConvert(Func<object, object> func)
        {
            return x =>
            {
                try
                {
                    return func(x);
                }
                catch
                {
                    return default(TTo);
                }
            };
        }
    }
}